#include <iostream>
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <iomanip>
#include <iostream>
#pragma comment(lib, "shlwapi.lib")
using namespace std;

inline bool TestSet(DWORD dwTarget, DWORD dwMask)
{
    return ((dwTarget & dwMask) == dwMask);
}

#define SHOWMASK(dwTarget, type)        \
    if (TestSet(dwTarget, PAGE_##type)) \
    {                                   \
        cout << "---" << #type;         \
    }

void ShowProtection(DWORD dwTarget)
{
    SHOWMASK(dwTarget, READONLY);
    SHOWMASK(dwTarget, GUARD);
    SHOWMASK(dwTarget, NOCACHE);
    SHOWMASK(dwTarget, READWRITE);
    SHOWMASK(dwTarget, WRITECOPY);
    SHOWMASK(dwTarget, EXECUTE);
    SHOWMASK(dwTarget, EXECUTE_READ);
    SHOWMASK(dwTarget, EXECUTE_READWRITE);
    SHOWMASK(dwTarget, EXECUTE_WRITECOPY);
    SHOWMASK(dwTarget, NOACCESS);
}

void WalkVM(HANDLE hProcess)
{
    SYSTEM_INFO si;
    ZeroMemory(&si, sizeof(si));
    GetSystemInfo(&si);

    MEMORY_BASIC_INFORMATION mbi;
    ZeroMemory(&mbi, sizeof(mbi));

    LPCVOID pBlock = (LPVOID)si.lpMinimumApplicationAddress;
    while (pBlock < si.lpMaximumApplicationAddress)
    {
        if (VirtualQueryEx(
                hProcess,
                pBlock,
                &mbi,
                sizeof(mbi)) == sizeof(mbi))
        {
            LPCVOID pEnd = (PBYTE)pBlock + mbi.RegionSize;
            TCHAR szSize[MAX_PATH];
            StrFormatByteSize(mbi.RegionSize, szSize, MAX_PATH);

            cout.fill('0');
            cout << hex << setw(8) << pBlock
                 << "-"
                 << hex << setw(8) << pEnd << "-->"
                 << (strlen(szSize) == 7 ? "(" : "(") << szSize
                 << ")";

            switch (mbi.State)
            {
            case MEM_COMMIT:
                printf("---Committed");
                break;
            case MEM_FREE:
                printf("---Free");
                break;
            case MEM_RESERVE:
                printf("---Reserved");
                break;
            }

            if (mbi.Protect == 0 && mbi.State != MEM_FREE)
            {
                mbi.Protect = PAGE_READONLY;
            }
            ShowProtection(mbi.Protect);

            switch (mbi.Type)
            {
            case MEM_IMAGE:
                printf("---Image");
                break;
            case MEM_MAPPED:
                printf("---Mapped");
                break;
            case MEM_PRIVATE:
                printf("---Private");
                break;
            }

            TCHAR szFilename[MAX_PATH];
            if (GetModuleFileName((HMODULE)pBlock,
                                  szFilename,
                                  MAX_PATH) > 0)
            {
                PathStripPath(szFilename);
                printf("---Module:%s", szFilename);
            }
            printf("\n");
            pBlock = pEnd;
        }
    }
}

void GetSize(HANDLE hProcess)
{
    PVOID pv[10000] = {0};
    if (!QueryWorkingSet(hProcess, pv, sizeof(pv)))
    {
        cout << "QueryWorkingSet Failed!" << endl;
    }
    else
    {
        for (unsigned int i = 0; i < 10000; i++)
        {
            if (pv[i] != NULL)
            {
                if (i == 0)
                    cout << "TotalNum : " << hex << pv[i] << endl;
                else
                    cout << '\t' << i << "  pv : " << hex << pv[i] << endl;
            }
            else
            {
                break;
            }
        }
    }

    cout << endl
         << endl;
}

int main()
{
    SYSTEM_INFO SI;
    GetSystemInfo(&SI);
    printf("--------------------------SYSTEM INFO-----------------------------------\n");
    printf("Lowest MainMemory Address: 0x%X\n", SI.lpMinimumApplicationAddress);
    printf("Highest MainMemory Address:  0x%X\n", SI.lpMaximumApplicationAddress);
    printf("PageSize %dk Byte\n", (SI.dwPageSize / 1024));
    printf("Virtual LargePageMinimum %dkB\n", (SI.dwAllocationGranularity / 1024));//虚拟大页面最小值
    printf("------------------------------------------------------------------------\n");

    PERFORMANCE_INFORMATION PI;
    WORD cb = sizeof(PI);
    WINAPI GetPerformanceInfo(&PI, cb);
    printf("--------------------------PERFORMANCE INFO-------------------------------\n");
    printf("CommitTotal:%d\n", PI.CommitTotal);             //系统当前提交的页面总数
    printf("CommitLimit:%d\n", PI.CommitLimit);             //系统当前可提交的最大页面总数
    printf("CommitPeak:%d\n", PI.CommitPeak);               //系统历史提交页面峰值
    printf("PhysicalTotal:%d\n", PI.PhysicalTotal);         //按页分配的总物理内存
    printf("PhysicalAvailable:%d\n", PI.PhysicalAvailable); //可用的物理内存
    printf("KernelTotal:%d\n", PI.KernelTotal);             //内存总量
    printf("KernelPaged:%d\n", PI.KernelPaged);             //分页池的大小
    printf("KernelNonpaged:%d\n", PI.KernelNonpaged);       //非分页池的大小
    printf("ProcessCount:%d\n", PI.ProcessCount);           //进程个数
    printf("-------------------------------------------------------------------------\n");

    MEMORYSTATUSEX statex;
    statex.dwLength = sizeof(statex);
    GlobalMemoryStatusEx(&statex);
    printf("--------------------------MemoryStatus-----------------------------------\n");
    printf("Physical Memory Usage Rate:%ld%%\n", statex.dwMemoryLoad);                      //内存的使用率
    printf("TotalPhys: %.2fGB.\n", (float)statex.ullTotalPhys / 1024 / 1024 / 1024);        //物理内存
    printf("AvailPhys: %.2fGB.\n", (float)statex.ullAvailPhys / 1024 / 1024 / 1024);        //可用物理内存
    printf("TotalPageFile:%.2fGB.\n", (float)statex.ullTotalPageFile / 1024 / 1024 / 1024); //提交的内存限制
    printf("AvailPageFile:%.2fGB.\n", (float)statex.ullAvailPageFile / 1024 / 1024 / 1024); //当前进程可以提交的最大内存量
    printf("TotalVirtual:%.2fGB.\n", (float)statex.ullTotalVirtual / 1024 / 1024 / 1024);   //虚拟内存
    printf("AvailVirtual:%.2fGB.\n", (float)statex.ullAvailVirtual / 1024 / 1024 / 1024);   //可用虚拟内存
    printf("AvailExtendedVirtual:%.2fByte.\n", statex.ullAvailExtendedVirtual);             //保留字段
    printf("-------------------------------------------------------------------------\n");

    printf("--------------------------PROCESS INFO-----------------------------------\n");
    PROCESSENTRY32 p;
    p.dwSize = sizeof(p);
    // 给系统内的所有进程拍一个快照
    HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    // 遍历进程快照，轮流显示每个进程的信息
    BOOL bMore = ::Process32First(hProcessSnap, &p);
    int con = 1;
    while (bMore != FALSE)
    {
        HANDLE htemp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, p.th32ProcessID);
        PROCESS_MEMORY_COUNTERS PMC;
        ZeroMemory(&PMC, sizeof(PMC));

        if (GetProcessMemoryInfo(htemp, &PMC, sizeof(PMC)) == TRUE)
        {
            printf("Process ID--->%10d    ", p.th32ProcessID);
            printf("Process Name--->%25s    ", p.szExeFile);
            printf("SIZE OF Process Vitural Memory--->%10fMB", (float)PMC.WorkingSetSize / 1024 / 1024);
            printf("peak--->%10fMB\n", (float)PMC.PeakWorkingSetSize / 1024 / 1024);
        }
        bMore = ::Process32Next(hProcessSnap, &p);
    }
    printf("-------------------------------------------------------------------------\n");

    printf("--------------------------PROCESS INFO-----------------------------------\n");
    int tar_process_id;
    int temp;
    HANDLE tar_process_handle;
    printf("SEARCH FOR A PROCESS,ENTER THE PROCESSID\n\n");
    scanf("%d", &tar_process_id);



    tar_process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, tar_process_id);
    WalkVM(tar_process_handle);



    
    cout << "Press to check the WorkingSet Info!" << endl;
    cin >> temp;
    GetSize(tar_process_handle);
    printf("-------------------------------------------------------------------------\n");

    system("pause");
    return 0;
}
